package org.dailydev.mojo.birt.runner.commandline;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.DefaultConsumer;
import org.codehaus.plexus.util.cli.Commandline.Argument;
import org.dailydev.mojo.birt.Parameter;
import org.dailydev.mojo.birt.runner.FormatEnum;
import org.dailydev.mojo.birt.runner.ModeEnum;

/**
 * Maven 2.0 BIRT Report Runner
 */
public class ReportRunner {

	private static final String REPORT_RUNNER_CLASS_NAME = "org.eclipse.birt.report.engine.api.ReportRunner";
	private static final String BIRT_HOME_SYSTEM_PROPERTY_NAME = "BIRT_HOME";

	private static final String ARGUMENT_NAME__CLASSPATH = "-classpath";
	private static final String ARGUMENT_NAME__MODE = "--mode";
	private static final String ARGUMENT_NAME__FORMAT = "--format";
	private static final String ARGUMENT_NAME__OUTPUT = "--output";
	private static final String ARGUMENT_NAME__PARAMETER = "--parameter";
	private static final String ARGUMENT_NAME__LOCALE = "--locale";
	private static final String ARGUMENT_NAME__PARAMETERS_FILE = "--file";
	private static final String ARGUMENT_NAME__PAGE = "--page";

	/**
	 * BIRT Runtime home
	 */
	private String birtHome;

	/**
	 * Reporting mode
	 */
	private ModeEnum mode = ModeEnum.RUNRENDER;

	/**
	 * Report format
	 */
	private FormatEnum format = FormatEnum.HTML;

	/**
	 * Output folder
	 */
	private File output;

	/**
	 * 
	 */
	private Commandline commandLine;

	/**
	 * Parent Mojo of this runner
	 */
	private final Mojo mojo;
	private File[] reports;
	private Parameter[] parameters;
	private String locale;
	private String parametersFile;
	private String page;
	private HTMLRenderConfig htmlConfig;

	/**
	 * @param mavenProject
	 * @param mode
	 */
	public ReportRunner(Mojo mojo, ModeEnum mode) {
		super();
		this.mojo = mojo;
		this.mode = mode;
	}

	/**
	 * @throws MojoExecutionException
	 */
	protected void defineBirtHomeSystemProperty() throws MojoExecutionException {
		Argument birtHomeArg = this.commandLine.createArgument();
		birtHomeArg.setValue("-DBIRT_HOME=" + getBirtHome() + "/ReportEngine");
	}

	/**
	 * Defines BIRT runner class.
	 */
	protected void defineClassName() {
		Argument classArg = this.commandLine.createArgument();
		classArg.setValue(REPORT_RUNNER_CLASS_NAME);
	}

	/**
	 * Defines BIRT runner classpath.
	 * 
	 * @throws MojoExecutionException
	 */
	protected void defineClasspath() throws MojoExecutionException {
		Argument classpathArg = this.commandLine.createArgument();
		classpathArg.setValue(ARGUMENT_NAME__CLASSPATH);
		Argument classpathArgValue = this.commandLine.createArgument();

		try {
			List files = FileUtils.getFiles(new File(getBirtHome(), "/ReportEngine/lib"), "**/*.jar", "");
			StringBuffer classpath = new StringBuffer();
			for (Iterator iterator = files.iterator(); iterator.hasNext();) {
				File jarFile = (File) iterator.next();
				classpath.append(jarFile.getAbsolutePath());
				if (iterator.hasNext()) {
					classpath.append(";");
				}
			}
			this.mojo.getLog().debug("BIRT runner classpath> " + classpath.toString());
			classpathArgValue.setValue(classpath.toString());
		} catch (IOException e) {
			throw new MojoExecutionException("Unable to get paths to jars for classpath", e);
		}
	}

	/**
	 * @throws MojoExecutionException
	 */
	protected void defineFormatArgument() throws MojoExecutionException {
		Argument formatArg = this.commandLine.createArgument();
		formatArg.setValue(ARGUMENT_NAME__FORMAT);
		Argument formatArgValue = this.commandLine.createArgument();
		formatArgValue.setValue(getFormat().getValue());
	}

	/**
	 * @throws MojoExecutionException
	 * 
	 */
	protected void defineFormatSpecificArguments() throws MojoExecutionException {
		if (this.format.equals(FormatEnum.HTML) && this.htmlConfig != null) {
			this.htmlConfig.defineArguments(this.commandLine);
		}
	}

	/**
	 * 
	 */
	protected void defineLocalizationArgument() {
		if (this.locale != null) {
			Argument localeArg = this.commandLine.createArgument();
			localeArg.setValue(ARGUMENT_NAME__LOCALE);
			Argument localeArgValue = this.commandLine.createArgument();
			localeArgValue.setValue(this.locale);
		}
	}

	/**
	 * @throws MojoExecutionException
	 */
	protected void defineModeArgument() throws MojoExecutionException {
		Argument modeArg = this.commandLine.createArgument();
		modeArg.setValue(ARGUMENT_NAME__MODE);
		Argument modeArgValue = this.commandLine.createArgument();
		modeArgValue.setValue(getMode().getValue());
	}

	/**
	 * 
	 */
	protected void defineOutputArgument() throws MojoExecutionException {
		Argument outputArg = this.commandLine.createArgument();
		outputArg.setValue(ARGUMENT_NAME__OUTPUT);
		Argument outputArgValue = this.commandLine.createArgument();
		outputArgValue.setValue(this.output.getAbsolutePath());
	}

	/**
	 * 
	 */
	protected void definePageArgument() {
		if (this.page != null) {
			Argument pageFileArg = this.commandLine.createArgument();
			pageFileArg.setValue(ARGUMENT_NAME__PAGE);
			Argument pageFileArgValue = this.commandLine.createArgument();
			pageFileArgValue.setValue(this.page);
		}
	}

	/**
	 * 
	 */
	protected void defineParamArguments() {
		for (int i = 0; i < this.parameters.length; i++) {
			Argument paramArg = this.commandLine.createArgument();
			paramArg.setValue(ARGUMENT_NAME__PARAMETER);
			Argument paramArgValue = this.commandLine.createArgument();
			paramArgValue.setValue(this.parameters[i].getName() + "=" + this.parameters[i].getValue());
		}
	}

	/**
	 * 
	 */
	protected void defineParametersFileArgument() {
		if (this.parametersFile != null) {
			Argument parametersFileArg = this.commandLine.createArgument();
			parametersFileArg.setValue(ARGUMENT_NAME__PARAMETERS_FILE);
			Argument parametersFileArgValue = this.commandLine.createArgument();
			parametersFileArgValue.setValue(this.parametersFile);
		}
	}

	/**
	 * @throws MojoExecutionException
	 */
	public void execute() throws MojoExecutionException {
		this.commandLine = new Commandline();
		this.commandLine.setExecutable("java");

		defineBirtHomeSystemProperty();
		defineClasspath();
		defineClassName();

		defineModeArgument();
		defineFormatArgument();

		defineFormatSpecificArguments();

		definePageArgument();

		defineLocalizationArgument();

		defineParametersFileArgument();
		defineParamArguments();

		defineOutputArgument();

		Argument reportArg = this.commandLine.createArgument();
		for (int i = 0; i < this.reports.length; i++) {
			this.mojo.getLog().debug("REPORT> " + this.reports[i].getAbsolutePath());
			reportArg.setValue(this.reports[i].getAbsolutePath());

			this.mojo.getLog().debug("Command line> " + this.commandLine.toString());

			try {
				CommandLineUtils.executeCommandLine(this.commandLine, new DefaultConsumer(), new DefaultConsumer());
			} catch (CommandLineException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Returns path to BIRT home as defined by 'birtHome' parameter or BIRT_HOME
	 * environment property if no 'birtHome' parameter defined.
	 * 
	 * @return path to BIRT home
	 * @throws MojoExecutionException
	 *             if BIRT_HOME environment property neither 'birtHome'
	 *             parameter is defined
	 */
	protected String getBirtHome() throws MojoExecutionException {
		checkBirtHomeSpecified();
		if (this.birtHome != null) {
			return this.birtHome;
		} else {
			return System.getenv(BIRT_HOME_SYSTEM_PROPERTY_NAME);
		}
	}

	/**
	 * @return the format
	 * @throws MojoExecutionException
	 */
	public FormatEnum getFormat() throws MojoExecutionException {
		return this.format;
	}

	/**
	 * @return
	 */
	public String getLocale() {
		return this.locale;
	}

	/**
	 * @return
	 * @throws MojoExecutionException
	 */
	public ModeEnum getMode() throws MojoExecutionException {
		return this.mode;
	}

	/**
	 * @return
	 */
	public File getOutput() {
		return this.output;
	}

	/**
	 * @return
	 */
	public String getPage() {
		return this.page;
	}

	/**
	 * @return
	 */
	public Parameter[] getParameters() {
		return this.parameters;
	}

	/**
	 * @return
	 */
	public String getParametersFile() {
		return this.parametersFile;
	}

	/**
	 * @return
	 */
	public File[] getReports() {
		return this.reports;
	}

	/**
	 * Checks if 'birtHome' parameter or BIRT_HOME environment property is
	 * defined
	 * 
	 * @throws MojoExecutionException
	 *             if BIRT_HOME environment property neither 'birtHome'
	 *             parameter is defined
	 */
	protected void checkBirtHomeSpecified() throws MojoExecutionException {
		if (this.birtHome == null && System.getenv(BIRT_HOME_SYSTEM_PROPERTY_NAME) == null) {
			throw new MojoExecutionException(
					"BIRT_HOME environment property or 'birtHome' parameter should be defined.");
		}
	}

	/**
	 * Sets 'birtHome' parameter value
	 * 
	 * @param birtHome
	 */
	public void setBirtHome(String birtHome) {
		this.birtHome = birtHome;
	}

	/**
	 * @param format
	 *            the format to set
	 * @throws MojoExecutionException
	 */
	public void setFormat(FormatEnum format) throws MojoExecutionException {
		this.format = format;
	}

	/**
	 * @param htmlConfig
	 */
	public void setHtmlConfig(HTMLRenderConfig htmlConfig) {
		this.htmlConfig = htmlConfig;
	}

	/**
	 * @param locale
	 */
	public void setLocale(String locale) {
		this.locale = locale;
	}

	/**
	 * @param output
	 */
	public void setOutput(File output) {
		this.output = output;
	}

	/**
	 * @param page
	 */
	public void setPage(String page) {
		this.page = page;
	}

	/**
	 * @param parameters
	 */
	public void setParameters(Parameter[] parameters) {
		this.parameters = parameters;
	}

	/**
	 * @param parametersFile
	 */
	public void setParametersFile(String parametersFile) {
		this.parametersFile = parametersFile;
	}

	/**
	 * @param reports
	 */
	public void setReports(File[] reports) {
		this.reports = reports;
	}
}
